﻿using System.Diagnostics;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;

namespace System
{
  //[DebuggerStepThrough]
  public static class TypeExtensions
  {
    public static bool IsNullable(this Type t)
    {
      return !t.IsValueType || (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
    }
    public static bool IsGenericTypeOf<T>(this Type t) where T : class
    {
      return (t.IsGenericType && t.GetGenericTypeDefinition().UnderlyingSystemType == typeof(T));
    }
    public static Type GetCoreType(this Type t)
    {
      if (t != null && IsNullable(t))
      {
        if (!t.IsValueType)
        {
          return t;
        }
        else
        {
          return Nullable.GetUnderlyingType(t);
        }
      }
      else
      {
        return t;
      }
    }
    public static object GetPropertyValue(this Object obj, string propertyName)
    {
      if (obj.IsNull())
      {
        return null;
      }

      Type t = obj.GetType();
      return t.GetProperty(propertyName).GetValue(obj, null);
    }
    public static bool DoPropertyHasAttribute<T>(this PropertyInfo property) where T : Attribute
    {
      return (property.GetCustomAttributes(typeof(T), false).Length > 0);
    }
    public static T GetAttributeValueFromProperty<T>(this PropertyInfo property) where T : Attribute
    {
      return (T)(property.GetCustomAttributes(typeof(T), false).FirstOrDefault());
    }
    public static List<T> GetAttributeValuesFromProperty<T>(this PropertyInfo property) where T : Attribute
    {
      return property.GetCustomAttributes(typeof(T), false).Cast<T>().ToList();
    }
    public static bool IsNullable(this PropertyInfo property)
    {
      return property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>));
    }
    public static bool IsPrimitiveType(this PropertyInfo property)
    {
      string[] primitiveTypes = Enum.GetNames(typeof(TypeCode));
      string type = "";
      var t = property.PropertyType;

      if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
      {
        type = Nullable.GetUnderlyingType(t).Name;
      }
      else
      {
        type = t.Name;
      }

      return type.IsIn(primitiveTypes);
    }
     public static bool IsPrimitiveTypeIncludingArrays(this PropertyInfo property)
    {
      string[] primitiveTypes = Enum.GetNames(typeof(TypeCode));
      string type = "";

      var t = property.PropertyType;

      if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
      {
        type = Nullable.GetUnderlyingType(t).Name;
      }
      else if(t.HasElementType)
      {
        type = t.GetElementType().Name;
      }
      else
      {
        type = t.Name;
      }

      return type.IsIn(primitiveTypes);
    }
 }
}